﻿using Moq;
using NUnit.Framework;
using Rainbow.ObjectFlow.Engine;
using Rainbow.ObjectFlow.Framework;
using Rainbow.ObjectFlow.Interfaces;
using Shouldly;


namespace Objectflow.core.tests.ParallelSplit
{
    public class WhenDefiningParallelWorkflows 
    {
        private Workflow<string> _workflow;

        [SetUp]
        public void Given()
        {
            _workflow = new Workflow<string>();

        }

        [Test]
        public void ShouldCreateSequenceWithOperationsAdded()
        {
            _workflow.Do((a) => "red").And.Do((b) => "orange").And.Do((c) => "yellow").Then();
            Assert.That(_workflow.RegisteredOperations.Tasks.Count, Is.EqualTo(1));
            Assert.That(((ParallelInvoker<string>)_workflow.RegisteredOperations.Tasks[0].Command).RegisteredOperations.Count, Is.EqualTo(3));
        }

        [Test]
        public void Should_create_and_command()
        {
            _workflow.Do(x => "red").And.ShouldBeTypeOf<IAnd<string>>();
        }

        [Test]
        public void and_Should_return_self()
        {
            var and = new AndOperand<string>();
            and.And.ShouldNotBe(null);
        }

        [Test]
        public void Should_remove_operation_before_and()
        {
            //WorkflowBuilder<string> workflowBuilder = new SequentialBuilder<string>();
            var taskList = new TaskList<string>();
            var workflow = new Workflow<string>(new Dispatcher<string>(), taskList);
            var and = workflow.Do(x => "red").And;

            taskList.Tasks.Count.ShouldBe(0);
        }

        // test one level down
        [Test]
        public void Should_do_add_operation_to_parrallel_invoker()
        {
            var parallelSplitBuilder = new ParallelSplitBuilder<string>();
            var and = new AndOperand<string>(parallelSplitBuilder);
            and.Do(x => "red");
            parallelSplitBuilder.ParallelOperations.RegisteredOperations.Count.ShouldBe(1);
        }

        // and tests
        [Test, Ignore]
        public void notifies_add_operation_on_then()
        {
            var tasklist = new Mock<TaskList<string>>();
            var parallelSplitBuilder = new Mock<ParallelSplitBuilder<string>>();
            parallelSplitBuilder.Object.OperationAdded += tasklist.Object.OperationAdded;
            var and = new AndOperand<string>(parallelSplitBuilder.Object);
            and.Then();

            tasklist.Verify(x => x.OperationAdded(It.IsAny<OperationDuplex<string>>()), Times.Once());

        }

        [Test]
        public void workflow_Should_return_same_and_on_second_call()
        {
            var workflow = new Workflow<string>();
            var firstAnd = workflow.Do(x => "red").And;
            var sedondAnd = workflow.Do(x => "red").And;

            firstAnd.ShouldBe(sedondAnd);
        }

        [Test]
        public void Should_invoke_then_on_calling_workflow()
        {
            var workflow = new Mock<Workflow<string>>();

            var andOperand = new AndOperand<string>(workflow.Object, new ParallelSplitBuilder<string>());
            andOperand.Then();

            workflow.Verify(x=>x.Then());
        }
    }
}